package ${escapeKotlinIdentifiers(packageName)}.api

import ${escapeKotlinIdentifiers(packageName)}.BuildConfig
import ${escapeKotlinIdentifiers(packageName)}.api.service.ContentService
import ${escapeKotlinIdentifiers(packageName)}.api.interceptor.AuthTokenInterceptor

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.readystatesoftware.chuck.ChuckInterceptor

import java.io.File
import java.util.concurrent.TimeUnit

import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSession

import io.ganguo.library.BaseContext
import io.ganguo.library.Config
import io.ganguo.library.http.cookie.CookieJarImpl
import io.ganguo.library.http.cookie.store.PersistentCookieStore
import io.ganguo.library.http.interceptor.APILogInterceptor
import io.ganguo.library.http.interceptor.CacheInterceptor
import io.ganguo.library.util.AppUtils
import okhttp3.Cache
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory

enum class APIServicePath constructor(var rawValue: String) {
    content("/content-service/v1/")
}

class APIClient private constructor() {
	val contentService: ContentService

	val cookieJar: CookieJarImpl

	init {
    	val gsonInstance = createGson()
    	cookieJar = CookieJarImpl(PersistentCookieStore(BaseContext.getInstance()))

        contentService = Retrofit.Builder()
                .baseUrl(BuildConfig.API_BASE_URL + APIServicePath.content.rawValue)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gsonInstance))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(createHttpBuilder())
                .build()
                .create(ContentService::class.java)
	}

  	private fun createGson(): Gson {
  		 return GsonBuilder()
  		   			.serializeNulls()
                	.create()
	}

	/**
     * 初始化网络配置，以及登录token
     */
    private fun createHttpBuilder(): OkHttpClient {
        val okHttpClientBuilder = OkHttpClient.Builder()
                .cookieJar(cookieJar)
                .cache(createOkhttpCache())
                .connectTimeout(30000, TimeUnit.MILLISECONDS)
                .readTimeout(30000, TimeUnit.MILLISECONDS)
                .retryOnConnectionFailure(true)
                .followRedirects(false)
                .followSslRedirects(false)
                .hostnameVerifier { _, _ -> true }
                .addInterceptor(CacheInterceptor())
                .addNetworkInterceptor(CacheInterceptor())

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            //Android 4.1以下无条件信任所有Https网站
            val sslParams = HttpsUtils.getSslSocketFactory(null, null, null)
            okHttpClientBuilder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            //Android 4.1以上,Android 5.0以下打开支持TLS1.1,TLS1.2
            var sslContext: SSLContext? = null
            try {
                sslContext = SSLContext.getInstance("TLS")
                try {
                    sslContext.init(null, null, null)
                } catch (e: KeyManagementException) {
                    e.printStackTrace()
                }
                val socketFactory = Tls12SocketFactory(sslContext?.socketFactory)
                okHttpClientBuilder.sslSocketFactory(socketFactory, HttpsUtils.UnSafeTrustManager())
            } catch (e: NoSuchAlgorithmException) {
                e.printStackTrace()
            }
        }

        okHttpClientBuilder.addInterceptor(AuthTokenInterceptor())

        if(BuildConfig.DEV_MODE){
            okHttpClientBuilder.addInterceptor(APILogInterceptor())
            okHttpClientBuilder.addInterceptor(ChuckInterceptor(AppUtils.getApp()))
        }

        return okHttpClientBuilder.build()
    }

    private fun createOkhttpCache(): Cache {
        val cacheFile = File(Config.getNetworkCachePath())
        return Cache(cacheFile, (1024 * 1024 * 100).toLong())
    }

   companion object {
   		private val apiClient: APIClient = APIClient()

        fun getInstance(): APIClient = apiClient
   }
}
